Core DNS

개요

코어 DNS는 쿠버네티스에서 사용되는 DNS 서버 애드온이다.
원래는 별개의 CNCF 프로젝트이나, 실질적으로 이거 말고 쓰이는 다른 대안이 없어 그냥 쿠버네티스 DNS라고 해도 상관 없다.
그래서 이 문서에서는 쿠버네티스 dns 방식에 대한 일체의 설명을 곁들인다.[1]

4.RESOURCE/KNOWLEDGE/Kubernetes/클러스터/클러스터에서 서비스에도, 파드도 고유한 ip를 부여받는다.
근데 통신할 때 ip 쓰는 찐따송구스럽다가 어딨냐 ㅋㅋ
당연히 쿠버네티스도 내부에서 통신할 때 DNS를 활용할 수 있도록 설계됐다.

원래 쿠버네티스에는 kube-dns라는 dns 서버가 어플리케이션이 있었다.
근데 이걸 조금 더 확장하는 애드온이 현재 거의 표준이 돼버린 것이다.
그래서 kube-system에서 확인해보면 kube-dns라는 이름의 서비스를 확인할 수 있다.
이를 통해 추후에 다른 dns 애드온을 사용한다고 해도 클러스터의 모든 dns는 kube-dns 서비스를 사용하므로 문제가 없게 된다.

클러스터 도메인

클러스터의 모든 파드, 서비스는 기본적으로 도메인이 부여된다.
이들만이 내부에서 IP를 가지니까 어찌보면 당연한 것 같기도
각 대상에게 어떤 식으로 도메인이 부여되는지부터 보자면..

여기에서 cluster.local은 클러스터 도메인으로, 클러스터를 구축하는 시점에 설정할 수 있다. 근데 커스텀하는 사람을 본 적이 없다
이렇게 지정된 도메인 네임을 반드시 FQDN(Fully Qualified Domain Name)으로 전부 나열해서 호출할 필요는 없다.

SRV?

아직 DNS 문서를 안 만들어서 남기는데, 이건 사용되는 프로토콜과 포트까지 함께 리턴한다.
한 도메인에 여러 서비스가 있을 때 사용하면 좋다.
ip 별 가중치도 부여할 수 있는, 일반 a 레코드의 확장 버전이랄까.

여담으로 .spec.setHostnameAsFQND=True 스펙이 돼있으면 파드 내부에서 hostname을 조회했을 때 FQDN이 나온다.
근데, 원래 리눅스에서는 호스트네임이 64글자 이상 될 수 없기 때문에 FQDN이 이상 넘어간다면 에러가 난다.
이런 걸 체크할 때는 Admission Webhook을 사용하는 게 좋다.

도메인 질의 구조

그래서 이 도메인을 어떻게 IP와 매칭시킬 것인가?
당연히 DNS 서버에 질의를 해야 한다.
그런데 이 도메인 네임은 당연히 클러스터 내부에서만 사용되기 때문에 클러스터 내부 DNS 서버에 질의를 해야 한다.
이때 해당 질의를 받는 서버가 바로 Core DNS이다.

각 파드가 생성될 때 kubelet/etc/resolv.conf에 클러스터 도메인이라 Core DNS에게 질의해야 하는 도메인에 대한 설정을 넣어준다.

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

이런 식으로 설정을 넣기 때문에 같은 네임스페이스에서는 뒤를 다 떼어먹고, 다른 네임스페이스면 네임스페이스까지만 붙여넣어서 질의가 가능한 것이다.
가령 default 네임스페이스의 파드가 naver.com 이란 도메인에 대해 질의를 한다고 생각해보자.
그럼 실제로 다음의 dns 질의들이 날아가게 된다.

ndots 5개(루트 도메인 포함) 제한으로 여기까지 질의하게 될 것이다.
이러한 방식은 당연히 DNS 서버에 과도한 부하를 안길 수 있기 때문에 ndots 값을 작게 유지하는 것이 최적화 전략 중 하나이다.
ndots는 도메인을 FQDN으로 인식하기 위한 점의 개수를 설정하는 옵션으로, 5개라고 한다면 도메인에 .이 5개 찍힐 때 FQDN으로 인식하고 뒤에 search 절의 도메인들을 붙여보는 실험을 하지 않는다.

그럼 실제 질의는 어떻게 이뤄질까?
아주 간단하게 도메인 질의 과정을 보자면 이런 식으로 이뤄진다.

(참고로 초록색 2번 플로우에서 파드 B는 절대로 저런 도메인을 가질 리 없지만 보기 편하라고 저렇게 적었다.)
클러스터의 컨테이너들은 자신 파일시스템에 /etc/resolv.conf의 내용을 바탕으로 질의할 DNS 서버를 정한다.
해당 값은 kubelet이 생성 시점에 넣어주는 것으로, 싫다면 kubelet 플래그에 --resolv-conf=""를 설정해서 커스텀 해주면 된다.
아무튼 이 resolv.conf 파일에는 항상 10.96.0.10과 같은 식으로 무조건 Core dns의 서비스 IP가 적힌다.
그래서 모든 도메인 질의는 무조건 Core DNS를 통해 이뤄지게 된다.

이때 Core DNS는 받은 도메인에 따라 크게 두 가지 동작을 하게 된다.

Core DNS 설정

다시 설명하자면 Core DNS는 클러스터의 DNS 서버이다.
클러스터를 구축할 때 kubeadm 등으로 같이 설치할지 옵션을 넣을 수 있으며, 일반 디플로이먼트로 배포된다.
달리 말하자면 CNI가 배치되지 않으면 IP를 부여받지 못하고 pending 상태에 머무른다.

Core DNS의 설정은 ConfigMap으로 관리된다.
DNS 서버 워크로드 자체는 이 설정을 마운팅하여 기동되기에 동적으로 설정이나 기능을 넣을 수 있다.[3]

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }    

이런 식으로 kube-system 네임스페이스에 coredns라는 이름으로 ConfigMap을 넣어주면 된다.
각 절에 대한 설명을 조금 해보자면..

여기다 추가 설정을 해도 된다.

consul.local:53 {
    errors
    cache 30
    forward . 10.150.0.1
}

Consul을 사용한다면 10.150.0.1에 dns 서버가 새로 서는데, 이쪽으로 dns 쿼리를 설정해주는 방식이다.

참고사항.
coredns는 스텁도메인 및 네임서버에 대한 fqdn을 지원하지 않는다.
fqdn 네임서버 설정은 전부 생략된다고 한다.

기타 - 파드 DNS 설정

여기는 파드에 DNS 관련 설정 필드들에 대해 간략하게 다룬다.

정책

파드마다 .spec.dnsPolicy 필드를 통해 DNS 정책을 지정할 수 있다.

헷갈리면 안 되는 게, 아무 설정 안 하면 기본값이 ClusterFirst다;;
Default에 낚이면 안 된다..

설정

파드에 resolve.conf에 추가되는 문자열 설정인데, 위의 정책이 None일 때는 필수적으로 설정돼야 한다.

  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 192.0.2.1 # this is an example
    searches:
      - ns1.svc.cluster-domain.example
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"
      - name: edns0

이 이렇게 된 예시는 아래처럼 resolv.conf에 추가된다.

nameserver 1.2.3.4
search ns1.svc.cluster-domain.example my.dns.search.suffix
options ndots:2 edns0

options 부분은 조금 설명이 필요할 수 있겠다.
ndots는 FQDN으로 간주할 범위를 말한다.
2로 돼있으니, foo.bar.라는 식의 쿼리가 나오면 뒤에 추가 도메인을 붙이지 않고 바로 네임서버로 질의를 날린다.
edns0은 dns 프로토콜을 확장할 수 있게 해주는 기능이라고 한다.

dns 검색 도메인 리스트 제한

쿠버에서는 도메인 리스트가 32개를 넘거나, 전체 도메인의 길이가 2048자를 넘기전까지는 설정에 대한 제한을 크게 하지 않는다.
이 제한은 노드, 파드, dns 설정 파일에 각각 적용된다.

근데 컨테이너 런타임마다 이에 대한 제한이 개별 적용돼있을 수 있어서, 이 제한과 충돌이 일어나는 경우가 있었다고 한다.
Containerd 1.5.5, CRI-O 1.21에서 이런 이슈가 있었다고 한다.

관련 문서

이름 noteType created
Core DNS knowledge 2025-01-09
S-flannel dns 질의 실패 topic/shooting 2024-09-11

참고


  1. https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ ↩︎

  2. https://ssup2.github.io/blog-software/docs/theory-analysis/kubernetes-coredns/ ↩︎

  3. https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/ ↩︎